package com.javacv4axe.video;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;

import javax.imageio.ImageIO;

import org.axe.util.LogUtil;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.Rect;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter.ToIplImage;

import com.javacv4axe.core.AsynchronousFrameHandler;
import com.javacv4axe.core.FramePack;

/**
 * Http视频播放Handler
 */
public class HttpVideoHandler extends AsynchronousFrameHandler{
	private ServerSocket ss = null;
	private Set<Socket> socketSet = new HashSet<>();
	private Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();
	private ToIplImage toIplImageConverter = new ToIplImage();
	private int windowWidth;
	private int windowHeight;
	
	public HttpVideoHandler() {
		init();
	}
	
	/**
	 * 如果设置了输出窗口的大小，那么对CammeraWatcher中设置的后续handler也会有影响，后续的handler接受到的frame将是此处设置大小的frame
	 * @param windowWidth
	 * @param windowHeight
	 */
	public HttpVideoHandler(int windowWidth,int windowHeight) {
		this.windowWidth = windowWidth;
		this.windowHeight = windowHeight;
		init();
	}
	
	private void init(){
		try {
			ss = new ServerSocket(8888);
			
			new Thread("HttpVideoHandler Socket Server port 8888"){
				public void run() {
					while(true){
						try {
							Socket socket = ss.accept();
							InputStream inputStream = socket.getInputStream();
							byte[] httpRequest = new byte[1024];
							int readLen = inputStream.read(httpRequest, 0, httpRequest.length);
							if(readLen <= 0){
								continue;
							}
							String requestHeader = new String(httpRequest,0,readLen);
							if(!requestHeader.startsWith("GET")){
								continue;//排除掉option请求等，只能是GET方式的请求有效。
							}
							
							OutputStream outputStream = socket.getOutputStream();
							outputStream.write(("HTTP/1.1 200 OK\r\n"+
												"Server: OpenMV\r\n"+
												"Content-Type: multipart/x-mixed-replace;boundary=openmv\r\n"+
												"Cache-Control: no-cache\r\n"+
												"Pragma: no-cache\r\n\r\n").getBytes());
							outputStream.flush();
							synchronized (socketSet) {
								socketSet.add(socket);
								if(debug()){
									LogUtil.log("new connection!socketSet.size:"+socketSet.size());
								}
								listenOnNewConnection();
							}
						} catch (IOException e) {}
					}
				};
			}.start();
		} catch (IOException e) {
			LogUtil.error(e);
		}
	}
	
	/**
	 * 新的视频请求连接进来后的操作
	 */
	public void listenOnNewConnection(){
		//留给开发者自行扩展
	}
	
	@Override
	public void cacheFrame(FramePack framePack) {
		if(windowWidth > 0 && windowHeight > 0){
			//如果设置了输出窗口大小，那么就要改变图像大小，设置ROI
			Frame frame = framePack.getFullFrame();
			int startX = (frame.imageWidth-windowWidth)/2;
			int startY = (frame.imageHeight-windowHeight)/2;
			if(startX >= 0 && startY >= 0){
				Mat mat = new Mat((Mat)frame.opaque, new Rect(startX,startY,windowWidth,windowHeight));
				opencv_core.flip(mat, mat, 1);//1：水平翻转，0：垂直翻转，<0：双向翻转
				frame = toIplImageConverter.convert(mat);
				framePack.setEditFrame(frame);//保存到上下文的editFrame中，给后续hanle用
			}
		}
		synchronized (socketSet) {
			Set<Socket> removeSet = new HashSet<>();
			for(Socket s:socketSet){
				try {
					OutputStream outputStream = s.getOutputStream();
					BufferedImage bi = java2DFrameConverter.getBufferedImage(framePack.getEditFrame());
					ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
					ImageIO.write(bi, "jpg", buffer);
					byte[] imgData = buffer.toByteArray();
					outputStream.write(("\r\n--openmv\r\n"+
										"Content-Type: image/jpg\r\n"+
										"Content-Length:"+imgData.length+"\r\n\r\n").getBytes());
					outputStream.write(imgData);
				} catch (Exception e) {
					try {
						s.close();
					} catch (Exception e2) {}
					removeSet.add(s);
					if(debug()){
						LogUtil.log("close connection!socketSet.size:"+(socketSet.size()-removeSet.size()));
					}
				}
			}
			socketSet.removeAll(removeSet);
		}
		countCacheFrameFps();
	}
	
	public Set<Socket> getSocketSet() {
		return socketSet;
	}
	
	@Override
	public String name() {
		return "web";
	}
	
	@Override
	public final boolean handle(FramePack framePack) {
		return false;//什么都不做
	}
}
